package edu.msse.signup.service;

import java.util.List;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.text.DateFormat;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.PersistenceException;
import javax.mail.Multipart;
import javax.jms.Session;
import javax.jms.JMSException;
import javax.jms.Message;

import org.springframework.orm.jpa.JpaCallback;
import org.springframework.orm.jpa.support.JpaDaoSupport;
import org.springframework.jms.core.SessionCallback;
import org.springframework.jms.core.MessageCreator;
import org.springframework.jms.core.JmsTemplate;
import org.apache.commons.mail.SimpleEmail;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.dom4j.Document;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;

import edu.msse.signup.domain.Event;
import edu.msse.signup.domain.Position;
import edu.msse.signup.domain.TimeSlot;
import edu.msse.signup.domain.Users;

public class VolunteerServiceImpl extends JpaDaoSupport implements VolunteerService {


    private JmsTemplate jmsTemplate;
    private HtmlEmail mailSender;

    public JmsTemplate getJmsTemplate() {
            return jmsTemplate;
    }

    public void setJmsTemplate(JmsTemplate jmsTemplate) {
        this.jmsTemplate = jmsTemplate;
    }


    public VolunteerServiceImpl() {
		super();
	}

    public void setMailSender(HtmlEmail mailSender) {
        this.mailSender = mailSender;
    }

    private HtmlEmail getMailSender() {
        return mailSender;
    }

    public void fillPositionTimeSlot(Position position, TimeSlot timeSlot,
			Users user) {

        if (timeSlot != null){
			TimeSlotService ts = new TimeSlotService();
			ts.addUser(timeSlot, user);
		}else {
			PositionService ps = new PositionService();
			ps.addUser(position, user);
		}

        try{
            final Position aPosition = position;
            final Users aUser = user;
            final Event event = position.getEvent();

            mailSender.setFrom("webmaster@volunteer.com","Volunteer Coordinators");
            mailSender.addTo(user.getEmailAddress(), user.getName());
            mailSender.setSubject("Volunteer Confirmation");
            String description = event.getDescription();
            Date startDate = event.getStartDate();
            Date endDate = event.getEndDate();
            DateFormat df = SimpleDateFormat.getDateInstance(SimpleDateFormat.SHORT);
            DateFormat tf = SimpleDateFormat.getTimeInstance(SimpleDateFormat.SHORT);
            mailSender.setHtmlMsg("You have signed up for the following:<br><b>Event: </b>"+event.getName()+"<br/>" +
                    "<b>Description: </b>" + (StringUtils.isNotBlank(description) ? description : "None") +
                    "<br /><b>Event Date: </b>" +
                    df.format(startDate)+ (DateUtils.isSameDay(startDate,endDate) ? "" : " to " + df.format(endDate)) +
                    "<br/><b>Event Time: </b>" + tf.format(startDate) + " to " + tf.format(endDate) +
                    "<br/>Click <a href=\"http://localhost:8080/faces/volunteerdetails?positionId=\""+position.getPositionId()+
                    (timeSlot != null ? "&timeslotId="+timeSlot.getTimeSlotId() : "") + ">here</a> " +
                            "for details on your position and/or timeslot.");
            mailSender.send();

         jmsTemplate.execute(new SessionCallback() {
            public Object doInJms(Session session) throws JMSException {
            	Document response = DocumentFactory.getInstance().createDocument();
            	Element root = DocumentFactory.getInstance().createElement("signup");
            	root.add(event.toXml());
            	root.add(aPosition.toXml());
            	root.add(aUser.toXml());
            	response.add(root);
                String msg = response.asXML();
                session.createProducer(session.createTopic("NotifySignupTopic")).
                        send(session.createTextMessage(msg));
                return null;
            }
        });

       
        }catch(Exception e){
            e.printStackTrace();
        }

    }

    
    @SuppressWarnings("unchecked")
	public List getOpenPositionsAndTimeSlots(Event event) {
    	
    	return getJpaTemplate().find(
   			 "select p from Position p where p.event = ? and (" +
   			 "(p in (select t.position from TimeSlot t where size(t.users) < t.numberOfVolunteers))" +
   			 "or (size(p.timeSlots) = 0 and size(p.users) < p.numberOfVolunteers))", event);
    	
   }

      
    @SuppressWarnings("unchecked")
	public List getFilledPositionsAndTimeSlots(Event event){
		return getJpaTemplate().find(
                "select p, t from TimeSlot t, Position p, Event e where e = ? and (" +
                "(size(p.users) >= p.numberOfVolunteers and p in elements(e.positions)) or " +
                "(p = t.position and size(t.users) >= t.numberOfVolunteers and p in elements(e.positions)))", event);
		
	}

    public boolean unFillPosition(int userId, int positionId){
    	Users user = getJpaTemplate().find(Users.class, userId);
    	Position position = getJpaTemplate().find(Position.class, positionId);
    	
    	EntityManager em = getJpaTemplate().getEntityManagerFactory().createEntityManager();
    	EntityTransaction tx = em.getTransaction();
        try {
            tx.begin();
            position=em.merge(position);
            user = em.merge(user);
            position.getUsers().remove(user);
            user.getPositions().remove(position);
            em.persist(position);
            em.persist(user);
            tx.commit();
            return true;
            
        } catch (Exception x) {
        	x.printStackTrace();
        	tx.rollback();
        	return false;
            
        }
    }
    
    public boolean unFillTimeSlot(int userId, long timeSlotId){
    	final Users user = getJpaTemplate().find(Users.class, userId);
    	final TimeSlot timeslot = getJpaTemplate().find(TimeSlot.class, timeSlotId);
    	
    	return (Boolean) getJpaTemplate().execute(new JpaCallback() {
    		
			public Object doInJpa(EntityManager em) throws PersistenceException {
				EntityTransaction tx = em.getTransaction();
		        try {
		        	tx.begin();
		            timeslot.getUsers().remove(user);
		            user.getTimeSlots().remove(timeslot);
		            TimeSlot mergeTimeSlot =em.merge(timeslot);
		            Users mergedUser = em.merge(user);
		            em.persist(mergeTimeSlot);
		            em.persist(mergedUser);
		            tx.commit();
		            return true;
		            
		        } catch (Exception x) {
		        	x.printStackTrace();
		        	tx.rollback();
		        	return false;
		            
		        }
			}});
    	
    	
    }
}
